//! 全局板卡信息管理
#![feature(lazy_cell)]
#![allow(unsafe_code)]

use std::{
    collections::HashMap,
    sync::{Arc, LazyLock},
};

use dfs::inode::DfsInode;
use error::{SmkError, SmkResult};
use rcu::RcuLock;

/// 板卡返回结果
///
/// `SmkResult` 别名
pub type BInfoResult<T> = SmkResult<T>;

/// 板卡返回错误
///
/// `SmkError` 别名
pub type BInfoError = SmkError;

/// 板卡文件节点操作
pub use dfs;

/// 板卡架构平台
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum BoardArch {
    /// arm32 平台
    Arm,
    /// aarch64 平台
    AArch64,
    /// risc-v 平台
    Riscv,
}

impl BoardArch {
    /// 板卡架构平台名称
    pub fn name(&self) -> &'static str {
        match self {
            BoardArch::Arm => "arm",
            BoardArch::AArch64 => "aarch64",
            BoardArch::Riscv => "riscv",
        }
    }
}

/// 板卡信息接口实现
pub trait BoardInfoImpl {
    /// 返回板卡对应的架构平台
    fn arch(&self) -> BoardArch;
    /// 返回板卡名字
    fn name(&self) -> &'static str;
    /// 返回板卡基本信息
    fn info(&self) -> &'static str;
    /// 返回板卡相信信息
    fn info_long(&self) -> &'static str;
    /// 创建预配置
    ///
    /// # Errors
    /// 由板卡返回错误
    fn pre_config(&self, path: Arc<DfsInode>) -> BInfoResult<()>;
    /// 结束预配置
    ///
    /// # Errors
    /// 由板卡返回错误
    fn pre_config_end(&self, path: Arc<DfsInode>) -> BInfoResult<()>;
    /// 板卡创建
    ///
    /// # Errors
    /// 由板卡返回错误
    fn create_board(&self) -> BInfoResult<()>;
}

/// 板卡信息
pub struct BoardInfo {
    info: Box<dyn BoardInfoImpl>,
}

unsafe impl Send for BoardInfo {}
unsafe impl Sync for BoardInfo {}

static BOARDSINFO: LazyLock<RcuLock<HashMap<String, Arc<BoardInfo>>>> =
    LazyLock::new(|| RcuLock::new(HashMap::new()));

impl BoardInfo {
    /// 板卡架构平台
    pub fn arch(&self) -> BoardArch {
        self.info.arch()
    }

    /// 板卡名字
    pub fn name(&self) -> &'static str {
        self.info.name()
    }

    /// 板卡基本信息
    pub fn info(&self) -> &'static str {
        self.info.info()
    }

    /// 板卡详细信息
    pub fn info_long(&self) -> &'static str {
        self.info.info_long()
    }

    /// 预配置 board
    ///
    /// # Errors
    /// 由板卡返回错误
    pub fn pre_config(&self, path: Arc<DfsInode>) -> BInfoResult<()> {
        self.info.pre_config(path)
    }

    /// 结束预配置 board
    ///
    /// # Errors
    /// 由板卡返回错误
    pub fn pre_config_end(&self, path: Arc<DfsInode>) -> BInfoResult<()> {
        self.info.pre_config_end(path)
    }

    /// 创建 board
    ///
    /// # Errors
    /// 由板卡返回错误
    pub fn create_board(&self) -> BInfoResult<()> {
        self.info.create_board()
    }
}

/// 注册一个板卡
#[allow(clippy::missing_panics_doc)]
pub fn register_board(info: Box<dyn BoardInfoImpl>) {
    let board = Arc::new(BoardInfo { info });
    let key = format!("{}:{}", board.arch().name(), board.name());
    let mut lock = BOARDSINFO.write().unwrap();
    lock.insert(key, board);
}

/// 遍历所有板卡
#[allow(clippy::missing_panics_doc)]
pub fn boardinfo_for_each<F: FnMut(&str, &BoardInfo)>(mut f: F) {
    let lock = BOARDSINFO.read().unwrap();
    lock.iter().for_each(|(key, board)| f(key, board));
}

/// 获取对应的 boardinfo
#[allow(clippy::missing_panics_doc)]
pub fn boardinfo(key: &str) -> Option<Arc<BoardInfo>> {
    let lock = BOARDSINFO.read().unwrap();

    for (this, board) in lock.iter() {
        if this == key {
            return Some(board.clone());
        }
    }
    None
}
